<template>
  <div class="table-wrapper">
    <div class="table-header" v-if="header">{{ header }}</div>
    <div class="table-filter" v-if="filter">
      <slot name="filter">
        <Form ref="form" :form="filterForm" @submit="submitForm"></Form>
      </slot>
    </div>
    <slot name="operator"></slot>
    <slot name="selection">
      <div style="display: inline-block; margin-bottom: 15px" v-if="selection">
        <el-button size="small" plain type="success">
          已选：{{ multipleSelection.length }}个
        </el-button>
        <el-button size="small" type="warn" @click="clearSelection">
          清空所有
        </el-button>
      </div>
    </slot>
    <div :class="['table-body', header || footer ? 'pad' : '']">
      <el-table v-if="columns.length" ref="table" :size="size" :data="dataSource" :stripe="stripe" :border="border"
                :max-height="height" :default-expand-all="defaultExpandAll" v-loading="loading" height="100%"
                @sort-change="sortChange" @select-all="selectionChange" @select="selectionChange"
                style="min-height: 100%" :headerCellStyle="{
'textAlign': 'center',
'fontWeight': 400,
'background': '#66b1ff',
'color': 'white',
}" :cell-style="{'textAlign': 'center' }">
        <template v-for="(column, index) in columns">
          <el-table-column v-bind="column" v-if="column?.type == 'expand'" :key="index + column.prop">
            <template slot-scope="props">
              <component :is="column.component || 'ExbandOrder'" :props="props"></component>
            </template>
          </el-table-column>
          <el-table-column v-bind="column" :key="index + column.prop" v-else>
            <template #default="scope" v-if="column.action">
              <el-button v-for="(e, i) in column?.action" :key="i" :type="e.type" :style="e.style || {}"
                         @click="$emit('action', e.options, scope.row)">
                {{ e.text }}
              </el-button>
            </template>
            <template #default="scope" v-else-if="column.showTip">
              <el-popover :width="scope.column.width || scope.column.minWidth || 350" trigger="hover">
                <template #reference>
                  <div class="tip-reference">
                    {{ scope.row[scope.column.property] }}
                  </div>
                </template>
                <template #default>
                  <div class="tip-content" @click="copyContent(scope)">
                    {{ scope.row[scope.column.property] }}
                  </div>
                </template>
              </el-popover>
            </template>
            <template #default="scope" v-else-if="column.render">
              <Render :scope="scope" :column="column" :pageSize="pageSize" :page-sizes="pageSizes"
                      :currentPage="currentPage"
                      @handleRender="(arg,params) => $emit('action', arg, scope.row, params)" />
            </template>
          </el-table-column>
        </template>
      </el-table>
    </div>
    <slot name="pagination">
      <div class="table-pagination" v-if="pagination">
        <span class="pagination-total"> 共 {{ total }} 条 </span>
        <el-pagination :total="total" @size-change="sizeChange" @current-change="currentChange" :pageSize="pageSize"
                       :currentPage="currentPage" background layout="sizes,prev, pager, next, jumper"></el-pagination>
      </div>
    </slot>
    <slot name="footer">
      <div class="table-footer" v-if="footer">{{ footer }}</div>
    </slot>
  </div>
</template>

<script>
import Render from "@/assets/js/Render.js";
import { copy } from "iclipboard";
import _ from "lodash";

export default {
  name: "Table",
  components: {
    Render,
  },
  props: {
    filter: {
      type: Boolean,
      default: false,
    },
    total: {
      type: Number,
      default: 0,
    },
    header: {
      type: String,
      default: "",
    },
    footer: {
      type: String,
      default: "",
    },
    loading: {
      type: Boolean,
      default: false,
    },
    defaultExpandAll: {
      type: Boolean,
      default: false,
    },
    stripe: {
      type: Boolean,
      default: false,
    },
    border: {
      type: Boolean,
      default: true,
    },
    pagination: {
      type: Boolean,
      default: true,
    },
    size: {
      type: String,
      default: "small",
    },
    height: {
      type: String,
      default: "550px",
    },
    pageSizes: {
      type: Array,
      default: () => [5,10,20,50,100],
    },
    selection: {
      type: Boolean,
      default: false,
    },
    form: {
      type: Object,
      default: () => ({
        search: {
          tag: "el-input",
          label: "查询条件",
          value: "",
          props: {
            clearable: true,
            placeholder: "请搜索...",
          },
        },
        date: {
          tag: "el-date-picker",
          value: [],
          props: {
            rangeSeparator: "至",
            startPlaceholder: "开始时间",
            endPlaceholder: "结束时间",
            type: "datetimerange",
          },
        },
      }),
    },
    dataSource: {
      type: Array,
      default: () => [],
    },
    columns: {
      type: Array,
      default: () => [
        { prop: "name", label: "Name", width: "180" },
        { prop: "date", label: "date" },
        { prop: "address", label: "Address" },
        { prop: "action", label: "Address", action: [] },
      ],
    },
  },
  data() {
    return {
      filterForm: JSON.parse(JSON.stringify(this.form)),
      pageSize: 20,
      currentPage: 1,
      formValue: {},
      multipleSelection: [],
    };
  },
  computed: {
    selectMap() {
      const res = {};
      const arr = this.multipleSelection;
      arr.forEach((e) => {
        res[e.id] = true;
      });
      return res;
    },
  },
  watch: {
    dataSource: {
      immediate: true,
      deep: true,
      handler() {
        this.initSelector();
      },
    },
  },
  mounted() {
    this.initTable();
  },
  methods: {
    initTable() {
      if (this.$refs.form) this.$refs.form.submit();
      else this.fetchTable();
    },
    initSelector() {
      setTimeout(() => {
        const { selection, selectMap, dataSource } = this;
        const ref = this.$refs.table;
        if (dataSource.length && selection && ref) {
          const rows = dataSource.filter((e) => selectMap[e.id]);
          if (rows.length)
            rows.forEach((row) => {
              ref.toggleRowSelection(row);
            });
        }
      }, 2);
    },
    copyContent: _.throttle(function (scope) {
      if (copy(scope.row[scope.column.property]))
        this.$message.success("复制成功");
      else this.$message.error("复制失败");
    }, 1000),
    selectionChange(rows, row) {
      if (rows.length) {
        rows = rows.filter((e) => !this.selectMap[e.id]);
        this.multipleSelection = [...rows, ...this.multipleSelection];
      } else {
        let datas = this.dataSource;
        if (row) datas = [row];
        const map = {};
        datas.forEach((e) => {
          map[e.id] = true;
        });
        this.multipleSelection = this.multipleSelection.filter(
          (e) => !map[e.id]
        );
        this.initSelector();
      }
    },
    clearSelection() {
      this.multipleSelection = [];
      const ref = this.$refs.table;
      ref && ref.clearSelection();
    },
    sortChange(props) {
      this.$emit("sortChange", props, this);
    },
    submitForm(form = {}) {
      this.currentPage = 1;
      this.formValue = form;
      this.fetchTable(form);
    },
    sizeChange(size) {
      this.pageSize = size;
      this.currentPage = 1;
      this.fetchTable(this.formValue);
    },
    currentChange(page) {
      this.currentPage = page;
      this.fetchTable(this.formValue);
    },
    fetchTable(form = this.formValue) {
      this.formValue = {
        ...form,
        pageNumber: this.currentPage,
        pageSize: this.pageSize,
      };
      this.$emit("fetchTable", this.formValue);
    },
  },
};
</script>

<style lang="less" scoped>
.table-wrapper {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;

  .table-header {
    padding-left: 14px;
    line-height: 40px;
    font-size: 12px;
    border-bottom: 1px solid #e2e8f0;
    background-color: #f9fafb;
    color: #1e293b;
  }

  .table-filter {
    :deep(.el-form--inline) {
      padding-bottom: 5px;

      .el-form-item {
        margin-bottom: 8px;
      }
    }
  }

  .operator-wrap {
    padding-bottom: 15px;
  }

  .table-body {
    flex: 1;
    overflow: hidden;
    background-color: #ffffff;

    &.pad {
      padding: 12px 20px 20px;
    }
  }

  .table-pagination {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    margin: 10px 5px;

    .pagination-total {
      color: #606266;
      font-size: 12px;
    }
  }

  .table-footer {
    padding-left: 14px;
    line-height: 40px;
    font-size: 12px;
    border-top: 1px solid #e2e8f0;
    background-color: #f9fafb;
    color: #1e293b;
  }

  :deep(tbody td) {
    background-color: white;
  }

  :deep(thead th) {
    font-weight: 500;
    background: #f9fafb;
    color: #6b7280;
  }

  :deep(tbody .cell) {
    color: #374151;
    padding-left: 7px;
    padding-right: 7px;
  }
}
</style>
